#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "Types.h"
#include "linux_msg.h"

ULONG LINUX_MSG_create(IN INT32 iProID, INOUT LINUX_MSG_s *pstQueue);
ULONG LINUX_MSG_delete(INOUT LINUX_MSG_s *pstQueue);
ULONG LINUX_MSG_send(IN INT32 msgId, IN LINUX_MSG_ITEM_s *pstSendItem);
ULONG LINUX_MSG_recv(IN INT32 msgId, IN LINUX_MSG_ITEM_s *pstSendItem);

/*************************************************
Function:     LINUX_MSG_QUEUE_init
Description:  初始化消息队列结构体
Input:        INOUT LINUX_MSG_s *pstQueue
Output:       INOUT LINUX_MSG_s *pstQueue
Return:       无
Author:       liuke
Date:         2019-01-17
Change: 
*************************************************/
VOID LINUX_MSG_init(INOUT LINUX_MSG_s *pstQueue)
{
    memset(pstQueue, 0, sizeof(*pstQueue));

    pstQueue->create = LINUX_MSG_create;
    pstQueue->send = LINUX_MSG_send;
    pstQueue->recv = LINUX_MSG_recv;
    pstQueue->RemoveID = LINUX_MSG_delete;

    return;
}

/*************************************************
Function:     LINUX_MSG_QUEUE_create
Description:  创建消息队列
Input:        IN INT32 iProID
              INOUT LINUX_MSG_s *pstQueue
Output:       INOUT LINUX_MSG_s *pstQueue
Return:       成功返回：STAT_SUCCEED，出错返回错误码
Author:       liuke
Date:         2019-01-17
Change: 
*************************************************/
ULONG LINUX_MSG_create(IN INT32 iProID, INOUT LINUX_MSG_s *pstQueue)
{
    key_t key = 0;

    key = ftok("./", iProID);
    if (key == -1)
    {
        perror("[LINUX_MSG_create] ftok ");
        return STAT_ERR_FTOK;
    }
    
    pstQueue->iMsgQueueId = msgget(key, IPC_CREAT | 0666 | IPC_EXCL);
    if (pstQueue->iMsgQueueId < 0)
    {
        printf("[%s %d] key %d exist!\n", __FUNCTION__, __LINE__, key);
        pstQueue->iMsgQueueId  = msgget(key, 0);
        if (pstQueue->iMsgQueueId  < 0)
        {
            perror("msgget ");
            return STAT_ERR_SYSTEM_V_MSGGET;
        }    
    }

    return STAT_SUCCEED;
}

/*************************************************
Function:     LINUX_MSG_send
Description:  消息队列发送
Input:        IN INT32 iMsgQueueId
              IN LINUX_MSG_ITEM_s *pstSendItem
Output:       None
Return:       ULONG
Author:       liuke
Date:         2019-01-17
Change: 
*************************************************/
ULONG LINUX_MSG_send(IN INT32 iMsgQueueId, IN LINUX_MSG_ITEM_s *pstSendItem)
{
    ULONG ulSendLen = 0;
    ULONG ulRet = STAT_SUCCEED;
    
    ulSendLen = sizeof(pstSendItem->stData) + pstSendItem->stData.ulLen;
    if (msgsnd(iMsgQueueId, pstSendItem, ulSendLen, IPC_NOWAIT) < 0)
    {
        perror("LINUX_MSG_QUEUE_send ");
        ulRet = STAT_ERR_SYSTEM_V_MSG_SEND;
    }

    return ulRet;
}

/*************************************************
Function:     LINUX_MSG_recv
Description:  消息队列读取
Input:        IN INT32 iMsgQueueId
              INOUT LINUX_MSG_ITEM_s *pstSendItem
Output:       INOUT LINUX_MSG_ITEM_s *pstSendItem
Return:       STAT_SUCCEED
Author:       liuke
Date:         2019-01-17
Change: 
*************************************************/
ULONG LINUX_MSG_recv(IN INT32 iMsgQueueId, IN LINUX_MSG_ITEM_s *pstSendItem)
{
    ULONG ulRecvLen = 0;
    ULONG ulRet = STAT_SUCCEED;

    ulRecvLen = msgrcv(iMsgQueueId, pstSendItem, pstSendItem->stData.ulLen,
                       pstSendItem->lType, IPC_NOWAIT) ;
    if (ulRecvLen < 0)
    {
        perror("LINUX_MSG_QUEUE_recv ");
        ulRet = STAT_ERR_SYSTEM_V_MSG_RECV;
        free(pstSendItem);
        pstSendItem->stData.ulLen = 0;
        return ulRet;
    }

    return ulRet;
}

/*************************************************
Function:     LINUX_MSG_delete
Description:  删除消息队列
Input:        INOUT LINUX_MSG_s *piMsgId
Output:       INOUT LINUX_MSG_s *piMsgId
Return:       
Author:       liuke
Date:         2019-01-17
Change: 
*************************************************/
ULONG LINUX_MSG_delete(INOUT LINUX_MSG_s *pstQueue)
{
    ULONG ulRet = STAT_SUCCEED;

    if(msgctl(pstQueue->iMsgQueueId, IPC_RMID, NULL) != 0)
    {
        perror("LINUX_MSG_QUEUE_delete ");        
        ulRet = STAT_ERR_SYSTEM_V_MSG_RMID;
    }

    pstQueue->iMsgQueueId = 0;

    return ulRet;
}

